home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 24 / AACD 24.iso / AACD / Magazine / Guru / enforcer / Enforcer.doc < prev    next >
Text File  |  1998-04-11  |  59KB  |  1,393 lines

  1. TABLE OF CONTENTS
  2.  
  3. Enforcer
  4. FindHit
  5. LawBreaker
  6. MMU
  7. Move4K
  8. RebootOff
  9. SegTracker
  10. Enforcer                                                             Enforcer
  11.  
  12.    NAME
  13.     Enforcer V37 - An advanced version of Enforcer - Requires V37
  14.  
  15.    SYNOPSIS
  16.     Enforcer - A tool to watch for illegal memory accesses
  17.  
  18.    FUNCTION
  19.     Enforcer will use the MMU in the advanced 680x0 processors
  20.     to set up MMU tables to watch for illegal accesses to memory
  21.     such as the low-page and non-existent pages.
  22.  
  23.     To use, run Enforcer (plus any options you may wish)
  24.     If you wish to detach, just use RUN >NIL: <NIL: to start it.
  25.     You can also start it from the Workbench.  When started from Workbench,
  26.     Enforcer will read the tooltypes of its icon or selected project icon
  27.     for its options.  (See the sample project icons)
  28.  
  29.     Enforcer should only be run *after* SetPatch.
  30.  
  31.     If SegTracker is running in the system when Enforcer is started,
  32.     Enforcer will use the public SegTracker seglist tracking for
  33.     identifying the hits.
  34.  
  35.    INPUTS
  36.     The options for Enforcer are as follows:
  37.  
  38.     QUIET/S        - This tells Enforcer not to complain about any invalid
  39.                      access and to just build MMU tables for cache setting
  40.                      reasons -- mainly used in conjunction with an
  41.                      Amiga BridgeBoard in a 68030 environment so that
  42.                      the system can run with the data cache turned on.
  43.                      In this case,
  44.                                     RUN >NIL: Enforcer QUIET
  45.                      should be placed into the startup-sequence right
  46.                      after SetPatch.
  47.  
  48.     TINY/S         - This tells Enforcer to output a minimal hit.  The
  49.                      output is basically the first line of the Enforcer
  50.                      hit.  (see below)
  51.  
  52.     SMALL/S        - This tells Enforcer to output the hit line, the
  53.                      USP: line, and the Name: line.  (This means that
  54.                      no register or stack display will be output)
  55.  
  56.     SHOWPC/S       - This tells Enforcer to also output the two lines
  57.                      that contain the memory area around the PC where
  58.                      the hit happened.  Useful for disassembly.
  59.                      This option will not do anything if QUIET, SMALL or
  60.                      TINY output modes are selected.
  61.  
  62.     STACKLINES/K/N - This lets you pick the number of lines of stack
  63.                      backtrace to display.  The default is 2.  If set
  64.                      to 0, no stack backtrace will be displayed.  There
  65.                      is NO ENFORCED LIMIT on the number of lines.
  66.  
  67.     STACKCHECK/S   - This option tells Enforcer that you wish all of
  68.                      the long words displayed in the stack to be checked
  69.                      against the global seglists via SegTracker.
  70.                      This will tell you what seglist various return
  71.                      addresses are on the stack.  If you are not
  72.                      displaying stack information in the Enforcer hit
  73.                      then STACKCHECK will have nothing to check.
  74.                      If you are displaying stack information, then
  75.                      each long word will be check and only those which
  76.                      are in one of the tracked seglists will be
  77.                      displayed in a SegTracker line.
  78.                      The output will show the PC address first and
  79.                      then work its way back on the stack such that you
  80.                      can read it from bottom up as the order of calling
  81.                      or from top down as the stack-frame backtrace.
  82.  
  83.     AREGCHECK/S    - This option tells Enforcer that you wish all of
  84.                      the values in the Address Registers checked via
  85.                      SegTracker, much like STACKCHECK.
  86.  
  87.     DREGCHECK/S    - This option tells Enforcer that you wish all of
  88.                      the values in the Data Registers checked via
  89.                      SegTracker, much like STACKCHECK.
  90.  
  91.     DATESTAMP/S    - This makes Enforcer output a date and time with each
  92.                      hit.  Due to the nature of the way Enforcer must
  93.                      work, the time can not be read during the Enforcer
  94.                      hit itself so the time output will be the last time
  95.                      value the main Enforcer task set up.  Enforcer will
  96.                      update this value every second as to try to not
  97.                      use any real CPU time.  The time displayed in the
  98.                      hit will thus be exact.
  99.                      (Assuming the system clock is correct.)
  100.                      The date is output before anything from the hit
  101.                      other than the optional introduction string.
  102.  
  103.     DEADLY/S       - This makes Enforcer a bit nasty.  Normally,
  104.                      when an illegal read happens, Enforcer returns 0
  105.                      as the result of this read.  With this option,
  106.                      Enforcer will return $ABADFEED as the read data.
  107.                      This option can make programs with Enforcer hits
  108.                      cause even more hits.
  109.  
  110.     FSPACE/S       - This option will make the special $00F00000 address
  111.                      space available for writing.  This is useful for
  112.                      those people with $00F00000 boards.  Mainly Commodore
  113.                      internal development work -- should only be used
  114.                      in that enviroment.
  115.  
  116.     VERBOSE/S      - This option will make Enforcer display information
  117.                      as to the mapping of the I/O boards and other
  118.                      technical information.  This information maybe useful
  119.                      in specialized debugging.
  120.  
  121.     LED/K/N        - This option lets you specify the speed at which
  122.                      the LED will be toggled for each Enforcer hit.
  123.                      The default is 1 (which is like it always was)
  124.                      Setting it to 0 will make Enforcer not touch
  125.                      the LED.  Using a larger value will make the
  126.                      flash take longer (such that it can be noticed
  127.                      when doing I/O models other than the default
  128.                      serial output)  The time that the flash will
  129.                      take is a bit more than 1.3 microseconds times
  130.                      the number.  So 1000 will be a bit more than
  131.                      1.3 milliseconds.  (Or 1000000 is a bit more than
  132.                      1.3 seconds.)
  133.  
  134.     PARALLEL/S     - This option will make Enforcer use the parallel port
  135.                      hardware rather than the serial port for output.
  136.  
  137.     RAWIO/S        - This option will make Enforcer stuff the hit report
  138.     (special IO)     into an internal buffer and then from the main
  139.                      Enforcer process output the results via the
  140.                      RawPutChar() EXEC debugging LVO.  Since the output
  141.                      happens on the Enforcer task it is possible for a
  142.                      hit that ends in a system crash to not be able to
  143.                      be reported.  This option is here such that tools
  144.                      which can redirect debugging output can redirect
  145.                      the Enforcer output too.
  146.  
  147.     FILE/K         - This option will make Enforcer output the hit report
  148.     (special IO)     but to a file insted of sending it to the hardware
  149.                      directly or using the RAWIO LVO.  A good example of
  150.                      such a file is CON:0/0/640/100/HIT/AUTO/WAIT.
  151.                      Another thing that can be done is to have a program
  152.                      sit on a named pipe and have Enforcer output to it.
  153.                      This program can then do whatever it feels like with
  154.                      the Enforcer hits.  (Such as decode them, etc.)
  155.                      *NOTE*  It is not a good idea to have Enforcer hits
  156.                      go to a file on a disk as if the system crashes
  157.                      during/after the Enforcer hit, the disk may
  158.                      become corrupt.
  159.  
  160.     STDIO/S        - This option will make Enforcer output the hit report
  161.     (special IO)     to STDOUT.  This option only works from the CLI as it
  162.                      requires STDOUT.  It is best used with redirection or
  163.                      pipes.
  164.  
  165.     BUFFERSIZE/K/N - This lets you set Enforcer's internal output buffer
  166.                      for the special I/O options.  This option is only
  167.                      valid with the RAWIO, FILE, or STDIO options.
  168.                      The minimum setting is 8000.  The default is 8000.
  169.                      Having the right amount of buffer is rather
  170.                      important for the special I/O modes.  The reason
  171.                      is due to the fact that no operating system calls
  172.                      can be made from a bus error.  Thus, in the
  173.                      special I/O mode, Enforcer must store the output
  174.                      in this buffer and, via some special magic,
  175.                      wake up the Enforcer task to read the buffer and
  176.                      write it out as needed.  However, if a task is
  177.                      in Forbid() or Disable() when the Enforcer hit
  178.                      happens, the Enforcer task will not be able to
  179.                      output the results of the hit.  This buffer lets
  180.                      a number of hits happen even if the Enforcer task
  181.                      was unable to do the I/O.  If the number of
  182.                      hits that happen before the I/O was able to
  183.                      run gets too large, the last few hits will either
  184.                      be cut off completely or contain only partial
  185.                      information.
  186.  
  187.     INTRO/K        - This optional introduction string will be output
  188.                      at the start of every Enforcer hit.  For example:
  189.                      INTRO="*NBad Program!"   The default is no string.
  190.  
  191.     PRIORITY/K/N   - This lets you set Enforcer's I/O task priority.
  192.                      The default for this priority is 99.  In some
  193.                      special cases, you may wish to adjust this.
  194.                      It is, however, recommended that if you are using
  195.                      one of the special I/O options (RAWIO, FILE, or
  196.                      STDIO) that you keep the priority rather high.
  197.                      If the priority you supply is outside of the
  198.                      valid task priority range (-127 to 127) Enforcer
  199.                      will use the default priority.
  200.  
  201.     NOALERTPATCH/S - This option disables the patching of the EXEC
  202.                      Alert() function.  Normally Enforcer will patch
  203.                      this function to provide information as to what
  204.                      called Alert() and to prevent the Enforcer hits
  205.                      that a call to Alert() would cause.
  206.  
  207.     ON/S           - Mainly for completeness.  If not specified, it
  208.                      is assumed you want to turn ON Enforcer.
  209.  
  210.     QUIT=OFF/S     - Tells Enforcer to turn off.  Enforcer can also be
  211.                      stopped by sending a CTRL-C to its process.
  212.  
  213.    RESULTS
  214.     When run, a set of MMU tables that map addresses that are not
  215.     in the system's address map as invalid are installed.  Enforcer
  216.     will then trap invalid access attempts and generate a diagnostic
  217.     message as to what the illegal access was.  The first memory page
  218.     (the one starting at location 0) is also marked as invalid as many
  219.     programming errors cause invalid access to these addresses.  Invalid
  220.     addresses are completely off limits to applications.
  221.  
  222.     When an    access violation happens, a report such as the following
  223.     is output.
  224.  
  225. 03-Apr-93  21:26:18
  226. WORD-WRITE to  00000000        data=4444       PC: 07895CA4
  227. USP:  078D692C SR: 0000 SW: 0729  (U0)(-)(-)  TCB: 078A2690
  228. Data: DDDD0000 DDDD1111 DDDD2222 DDDD3333 DDDD4444 DDDD5555 DDDD6666 DDDD7777
  229. Addr: AAAA0000 AAAA1111 AAAA2222 AAAA3333 AAAA4444 AAAA5555 07800804 --------
  230. Stck: 00000000 07848E1C 00009C40 078A30B4 BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB
  231. Stck: BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB 078E9048 00011DA8 DEADBEEF
  232. ----> 07895CA4 - "lawbreaker"  Hunk 0000 Offset 0000007C
  233. PC-8: AAAA1111 247CAAAA 2222267C AAAA3333 287CAAAA 44442A7C AAAA5555 31C40000
  234. PC *: 522E0127 201433FC 400000DF F09A522E 012611C7 00CE4EAE FF7642B8 0324532E
  235. Name: "New_Shell"  CLI: "lawbreaker"  Hunk 0000 Offset 0000007C
  236.  
  237. LONG-READ from AAAA4444                        PC: 07895CA8
  238. USP:  078D692C SR: 0015 SW: 0749  (U0)(F)(-)  TCB: 078A2690
  239. Data: DDDD0000 DDDD1111 DDDD2222 DDDD3333 DDDD4444 DDDD5555 DDDD6666 DDDD7777
  240. Addr: AAAA0000 AAAA1111 AAAA2222 AAAA3333 AAAA4444 AAAA5555 07800804 --------
  241. Stck: 00000000 07848E1C 00009C40 078A30B4 BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB
  242. Stck: BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB 078E9048 00011DA8 DEADBEEF
  243. ----> 07895CA8 - "lawbreaker"  Hunk 0000 Offset 00000080
  244. PC-8: 247CAAAA 2222267C AAAA3333 287CAAAA 44442A7C AAAA5555 31C40000 522E0127
  245. PC *: 201433FC 400000DF F09A522E 012611C7 00CE4EAE FF7642B8 0324532E 01266C08
  246. Name: "New_Shell"  CLI: "lawbreaker"  Hunk 0000 Offset 00000080
  247.  
  248. 25-Jul-93  17:15:06
  249. Alert !! Alert 35000000     TCB: 07642F70     USP: 07657C10
  250. Data: 00000000 DDDD1111 DDDD2222 DDDD3333 0763852A DDDD5555 DDDD6666 35000000
  251. Addr: AAAA0000 AAAA1111 AAAA2222 AAAA3333 AAAA4444 0763852A 07400810 --------
  252. Stck: 076385A0 00000000 0752EE9A 00002800 07643994 00000000 0762F710 076305F0
  253. ----> 076385A0 - "lawbreaker"  Hunk 0000 Offset 00000098
  254.  
  255.     Here is a breakdown of what these reports are saying:
  256.  
  257.     In the first report, the first line is the date stamp.
  258.  
  259.     The first line of each report describes the access violation
  260.     and where it happened from.  In the case of a WRITE, the data
  261.     that was being written will be displayed as well.  If an instruction
  262.     mode access caused the fault, there will be an (INST) in the line.
  263.  
  264.     The first line may also contain the BUS ERROR message.  This will
  265.     be displayed when an address that is valid in the system lists
  266.     causes a physical bus fault during the access.  This usually
  267.     will happen with plug-in cards or when a hardware problem causes
  268.     some form of system fault.  Watch out, if this does show up, your
  269.     system may be unstable and/or unreliable.
  270.  
  271.     The second line (starts USP:) displays the USER stack pointer (USP),
  272.     the status register (SR:), the special status word (SW:).  It then
  273.     displays the supervisor/user state and the interrupt level.  This
  274.     will be from (U0) to (U7) or (S0) to (S7)  (S=Supervisor)  Next
  275.     is the forbid state (F=forbid, -=not) and the disable state (D or -)
  276.     of the task that was running when the access fault took place.
  277.     Finally, the task control block address is displayed (TCB:)
  278.  
  279.     The next two lines contain the data and address register dumps from
  280.     when the access fault happened.  Note that A7 is not listed here.
  281.     It is the stack pointer and is listed as USP: in the line above.
  282.  
  283.     Then come the lines of stack backtrace.  These lines show the
  284.     data on the stack.  If the stack is in invalid memory, Enforcer will
  285.     display a message to that fact.
  286.  
  287.     If SegTracker was installed before Enforcer, the "---->" lines
  288.     will display in which seglist the given addresses are in based on the
  289.     global tracking that SegTracker does.  (See docs on SegTracker)
  290.     If no seglist match is found, no lines will be displayed.
  291.     One line will be displayed for each of the stack longwords asked
  292.     for (see the STACKCHECK option) and one line for the PC address of
  293.     the Enforcer hit.  (The PC line is always checked for is SegTracker
  294.     is installed.)  The lines are in order: hit, first stack find,
  295.     second stack find, etc.  This is useful for tracking down who
  296.     called the routine that caused the Enforcer hit.
  297.  
  298.     Next, optionally, comes the data around the program counter when the
  299.     access fault happened.  The first line (PC-8:) is the 8 long-words
  300.     before the program counter.  The second line starts at the program
  301.     counter and goes for 8 long words.
  302.  
  303.     The last line displays the name of the task that was running when
  304.     the access fault took place.  If the task was a CLI, it will display
  305.     the name of the CLI command that was running.  If the access fault
  306.     was found to have happened within the seglist of a loaded program,
  307.     the segment number and the offset from the start of the segment will
  308.     be displayed.  (Note that this works for any LoadSeg()'ed process)
  309.  
  310.     Note that the name will display as "Processor Interrupt Level x"
  311.     if the access happened in an interrupt.
  312.  
  313.     The other output that could happen is when a program or the OS
  314.     calls the EXEC Alert function.  Enforcer catches these calls
  315.     and will display the alert information as seen above.  (With the
  316.     date and time if needed)
  317.  
  318.    WARNING
  319.     Enforcer is for software testing.  In this role it is vital.
  320.     Software that causes Enforcer hits may not be able to run on
  321.     newer hardware.  (Enforcer hits of high addresses on systems not
  322.     running Enforcer but with a 68040 will most likely crash the system)
  323.     Future systems and hardware will make this even more important.  The
  324.     system can NOT survive software that causes Enforcer hits.
  325.  
  326.     However, Enforcer is NOT a system protector.  As a side effect, it
  327.     may well keep a system from crashing when Enforcer hits happen, but
  328.     it may just as well make the software crash earlier.  Enforcer is
  329.     mainly a development and testing tool.
  330.  
  331.     Enforcer causes    no ill effects with correctly working software.
  332.     If a program fails to work while Enforcer is active, you should
  333.     contact the developer of that program.
  334.  
  335.    NOTES
  336.     This is Enforcer V37.  Bryce Nesbitt came up with the original
  337.     "Enforcer" that has been instrumental to the improvement in the
  338.     quality of software on the Amiga.  The Amiga users and developers
  339.     owe him a great deal for this.  Thank you Bryce!  Enforcer V37,
  340.     however, is a greatly enhanced and more advanced tool.
  341.  
  342.     Enforcer V37 came about due to a number of needs.  These included
  343.     the need for more output options and better performance.  It also
  344.     marks the removal of all kludges that were in the older versions.
  345.     Also, some future plans required some of these changes...
  346.  
  347.     In addition, the complete redesign was needed in order to
  348.     support the 68040.  The internal design of Enforcer is now set up
  349.     such that CPU/MMU specific code can be cleanly accessed from the
  350.     general house keeping aspect of the code.  The MMU bus error
  351.     handling is, however, 100% CPU specific.
  352.  
  353.     Since AbsExecBase is in low memory, reads of this address are slower
  354.     with Enforcer running.  Caching AbsExecBase locally is highly
  355.     recommended since it is in CHIP memory and on systems with FAST
  356.     memory, it will be faster to access the local cached value. (In
  357.     addition to the performance increase when running Enforcer) Note
  358.     that doing many reads of location 4 will hurt interrupt performance.
  359.  
  360.     When the Amiga produces an ALERT, EXEC places some magic numbers
  361.     into some special locations in low memory.  The exact pattern
  362.     changes between versions of the operating system.
  363.  
  364.     Enforcer will patch the EXEC function ColdReboot() in an attempt to
  365.     "get out of the way" when someone tries to reboot the system.
  366.     Enforcer will clean up as much as possible the MMU tables and then
  367.     call the original LVO.  When Enforcer is asked to quit, it will
  368.     check to make sure it can remove itself from this LVO. If it can
  369.     not, it will not quit at that time.  If run from the shell, it will
  370.     display a message saying that it tried but could not exit.  Enforcer
  371.     will continue to be active and you can try later to deactivate it.
  372.  
  373.     Enforcer will also patch the EXEC function Alert() in an attempt to
  374.     provide better tracking of other events in the system.  It is also
  375.     patched such that dead-end alerts will correctly reset the system
  376.     and be displayed.  With this patch in place, the normal alerts will
  377.     not be seen but will be replaced by the Enforcer output shown
  378.     above.  See LawBreaker for a more complete example of this.
  379.  
  380.    68020 NOTES
  381.     The 68020 does not have a built-in MMU but has a co-processor
  382.     feature that lets an external MMU be connected.  Enforcer MMU code
  383.     is designed for use with 68851 MMU.  This is the some-what 68030
  384.     compatible MMU by Motorola.  Enforcer uses the same code for both
  385.     the 68030 and the 68020/68851.  For this reason, 68020/68851 users
  386.     should see the 68030 NOTES section.
  387.  
  388.    68030 NOTES
  389.     The 68030 uses cycle/instruction continuation and will
  390.     supply the data on reads and ignore writes during an access
  391.     fault rather than let the real bus cycle happen.  This means
  392.     that on a fault caused by MMU tables, no bus cycle to the
  393.     fault address will be generated.  (For those of you with analyzers)
  394.  
  395.     In some cases, the 68030 will have advanced the Program Counter
  396.     past the instruction by the time the access fault happens.
  397.     This is usually only on WRITE faults.  For this reason, the PC
  398.     may either point at the instruction that caused the fault or
  399.     just after the instruction that caused the fault.  (Which could
  400.     mean that it is pointing to the middle of the instruction
  401.     that caused the fault.)
  402.  
  403.     Note that there is a processor called 68EC030.  This processor
  404.     has a disabled or defective MMU.  However, it may function well
  405.     enough for Enforcer to think it has a fully functional MMU and
  406.     thus Enforcer will attempt to run.  However, even if it looks like
  407.     the MMU is functioning, it is not fully operational and thus may
  408.     cause strange system activity and even crashes.  Do not assume
  409.     that Enforcer is safe to use on 68EC030 systems.
  410.  
  411.    68040 NOTES
  412.     Enforcer, on the 68040, *requires* that the 68040.library be
  413.     installed and it requires an MMU 68040 CPU.  The 68EC040 does not
  414.     have a MMU.  The 68LC040 does have an MMU and is supported. Enforcer
  415.     will work best in a system with the 68040.library 37.10 or better
  416.     but it does know how to deal with systems that do not have that
  417.     version.
  418.  
  419.     Due to the design of the 68040, Enforcer is required to do a number
  420.     of things differently.  For example, the MMU page size can only be
  421.     either 8K or 4K.  This means that to protect the low 1K of memory,
  422.     Enforcer will end up having to mark the first 4K of memory as
  423.     invalid and emulate the access to the 3K of that memory that is
  424.     valid. For this reason Enforcer moves a number of possible
  425.     structures from the first 4K of memory to higher addresses.  This
  426.     means that the system will continue to run at a reasonable speed.
  427.     The first time Enforcer is run it may need to allocate memory for
  428.     these structures that it will move.  Enforcer can never return this
  429.     memory to the system.
  430.  
  431.     In addition to the fact that the 68040 MMU table size is different,
  432.     the address fault handling is also different.  Namely, the 68040 can
  433.     only rerun the cycle and not continue it like the 68030. This means
  434.     that on a 68040, the page must be made available first and then made
  435.     unavailable.  To make this work, Enforcer will switch the instruction
  436.     that caused the error into trace mode and let it run with a special
  437.     MMU setup.  When the trace exception comes in, the MMU is set
  438.     back to the way it was.  Enforcer does its best to keep debuggers
  439.     working.  Note, however, that the interrupt level during a trace of
  440.     a READ will end up being set to 7.  This is to prevent interrupts
  441.     from changing the order of trace/MMU table execution.  The level
  442.     will be restored to the original state before continuing.  Since T0
  443.     mode tracing is also supported, there are also some changes in the
  444.     way it operates.  T0 mode tracing is defined, on the 68040, to cause
  445.     a trace whenever the instruction pipeline needed to be reloaded.
  446.     While on the 68020/030 processors this was normally only for the
  447.     branch instructions, in the 68040 this includes a large number of
  448.     other instructions.  (Including NOP!)  Anyway, if an Enforcer hit
  449.     happens while in T0 tracing mode, the trace will happen even on
  450.     instructions that normally would not cause a T0 mode trace.  Since
  451.     this may actually help in debugging and because it was not possible
  452.     to do anything else, this method of operation is deemed acceptable.
  453.  
  454.     Another issue with the 68040 is that WRITE faults happen *after* the
  455.     instruction has executed.  (Except for MOVEM)  In fact, it is common
  456.     for the 68040 to execute one or more extra instructions before the
  457.     WRITE fault is executed.  This design makes the 68040 much faster,
  458.     but it also makes the Program Counter value that Enforcer can report
  459.     for the fault much less likely to be pointing to the instruction
  460.     that caused it.  The worst cases are sequences such as a write fault
  461.     followed by a branch instruction.  In these cases, the branch is
  462.     usually already executed before the write fault happens and thus the
  463.     PC will be pointing to the target of the branch.  There is nothing
  464.     that can be done within Enforcer to help out here.  You will just
  465.     need to be aware of this and deal with it as best as possible.
  466.  
  467.     Along with the above issue, is the fact that since a write fault may
  468.     be delayed, a read fault may happen before the write fault shows up.
  469.     Internally, enforcer does not do special processing for these and
  470.     they will not show up.  Since another hit was happening anyway, it
  471.     is felt that it is best to just not report the hit.  Along the same
  472.     lines, the hit generated from a MOVEM instruction may only show as a
  473.     single hit rather than 1 for each register moved.
  474.  
  475.     On the Amiga, MOVE16 is not supported 100%.  Causing an Enforcer hit
  476.     with a MOVE16 will cause major problems and maybe cause Enforcer or
  477.     your task to lock.  Since MOVE16 is not supported, this is not a
  478.     major issue.  Just watch out if you are using this 68040
  479.     instruction.  (Also, watch out for the 68040 CPU bug with MOVE16)
  480.  
  481.     The functions CachePreDMA(), CachePostDMA(), and CacheControl() are
  482.     patched when the 68040 MMU is turned on by Enforcer.  These
  483.     functions are patched such the issues with DMA and the 68040
  484.     COPYBACK data caches are addressed.  The 68040.library normally
  485.     deals with this, however since Enforcer turns on the MMU, the method
  486.     of dealing with it in the 68040.library will not work. For this
  487.     reason, Enforcer will patch these and implement the required fix for
  488.     when the MMU is on.  When Enforcer is asked to exit, it will check
  489.     if it can remove itself from these functions.  If it can not, it
  490.     will ignore the request to exit.  If Enforcer was run from the CLI,
  491.     it will print a message saying that it can not exit when the attempt
  492.     is made.
  493.  
  494.    68060 NOTES
  495.     Enforcer, on the 68060, *requires* that the 68060.library be
  496.     installed.  Due to the fact that various possible 68060.library
  497.     versions may exist, Enforcer tries to not second guess it.
  498.     Thus, Enforcer assumes that the 68060.library has all of the
  499.     same functionality as V37.30 or better of the 68040.library.
  500.  
  501.     It turns out that some of the 68060 libraries do not have the
  502.     same functionality of the 68040.library.  One common library
  503.     has elected not to handle Pre/Post DMA MMU table operations
  504.     when Enforcer installs its MMU table.  This results in some
  505.     DMA/Cache interactions.  Enforcer can not work around this
  506.     problem safely.  If you happen to have a 68060.library with
  507.     version 2.1 (19.07.96) you may be able to patch it to not
  508.     have this problem.  At offset $09BE there should be the
  509.     4-byte sequence $20 6D 00 04  Changing this to $4E 7A 88 06
  510.     will let it handle Enforcer's MMU tables too.  (The same
  511.     patch may work in other versions of the library)
  512.  
  513.     For implementers of 68060.library, see my notes as to what
  514.     had to be done in 68040.library for correct operation.
  515.     Note that this does not mean that Enforcer needs this.  The Amiga
  516.     system needs this to operate correctly.  Enforcer just may
  517.     cause these problems to become more evident.  The notes are only
  518.     in the AmigaGuide version of the Enforcer documentation.
  519.  
  520.     The 68060 exception model is full-restart, which means that
  521.     all instructions are re-run.  Both reads *and* writes.
  522.     This means that Enforcer can not tell you what the data
  523.     that would be written is, unlike the 68040 and earlier CPUs.
  524.     So, the output for a write will not include the data that
  525.     was to be written.  This does mean that faults happen
  526.     before the instruction is executed (usually) and thus the
  527.     reported PC will be more exact.  This restart model also
  528.     means that if an real bus-fault happens, Enforcer will be
  529.     unable to do much other than let it happen.  (The same is
  530.     true for reads on the 68040)  Enforcer maps all addresses
  531.     as either valid based on system configuration or invalid.
  532.     This is so that no address should cause a bus fault unless
  533.     the system configuration is incorrect and an address that
  534.     was marked valid actually causes a fault.
  535.  
  536.     Be sure to read the 68040 notes as the 68060 is a superset
  537.     of much of these notes.
  538.  
  539.     Due to the complexity of emulating access to lower memory and
  540.     the fact that the 68060 was introduced well after V39 kickstart,
  541.     it is highly recommended that you use V39 or better with 68060 CPUs.
  542.     This mainly has to deal with lower 4K of memory.  As of V38 of
  543.     exec.library, 68040/68060 processors would map out the lower 4K
  544.     of RAM rather than just 1K.  This was required since the newer
  545.     CPUs did not have page sizes less than 4K.
  546.  
  547.     It turns out that some 68060 CPU cards also have other hardware
  548.     on them.  This is not a problem, unless this hardware does not
  549.     autoconfigure.  Enforcer needs to know about hardware in the
  550.     system so it can map the MMU to that hardware.  If the hardware
  551.     is not true Amiga AutoConfig (as in no expansion.library entry)
  552.     then Enforcer has no way of knowing it exists.
  553.  
  554.     A common location for such hardware control registers to be
  555.     placed is in the reserved $00F00000 address range (known as
  556.     F-Space).  This 512K space was reserved for future Kickstart
  557.     growth.  It also has some magic in it so that you can wedge
  558.     special startup routines there for things like 68060 cards.
  559.     At least one vendor is doing all of this correctly and
  560.     has even made sure that expansion.library knows about the
  561.     hardware that is located in the $00F00000 address range.
  562.  
  563.     If, when running Enforcer, your machine does lock up *and*
  564.     when you run Enforcer with the VERBOSE option it does not
  565.     say that the $00F00000 address range is a "board address"
  566.     then you may wish to try the FSPACE option to see if this
  567.     is the reason.  If this does not fix the problem, you more
  568.     than likely have either a real bug or some other non-AutoConfig
  569.     hardware in your system.
  570.  
  571.    WRITING DEBUGGERS
  572.     If you wish to make a debugger that works with Enforcer to help
  573.     pinpoint Enforcer hits in the application and not cause Enforcer
  574.     hits itself, here are some simple tips and a bit of code.
  575.  
  576.    DEBUGGERS:  TRAPPING A HIT
  577.     To trap a hit requires a number of things to work.
  578.  
  579.     First, the debugger itself must never cause an Enforcer hit.
  580.     For help on that, see the "DEBUGGERS: NOT CAUSING A HIT"
  581.  
  582.     Second, the debugger must be global.  That is, you must be
  583.     able to deal with a task getting a hit that is not the task
  584.     under test.  There are a number of simple ways to deal with
  585.     this, and I will leave this up to the debugger writer.
  586.     (One method will be shown below)
  587.  
  588.     Third, the debugger must start *AFTER* Enforcer starts.
  589.     If it is started before Enforcer, the hits will not be
  590.     trapped.  (Note that this is not a problem)
  591.  
  592.     A very important point:  The code needs to be fast for
  593.     the special case of location 4.  This is shown in the
  594.     code below.  It is very important that this be fast.
  595.  
  596.     Note that it is much prefered that debuggers use the
  597.     method described below for trapping hits.  It should
  598.     be much more supportable this way as any of the tricky
  599.     work that may need to be done in the hit processing
  600.     will be handled by Enforcer itself.  If you wish the
  601.     hit decoded, you can capture the Enforcer output via a
  602.     pipe or some other method (such as RAWIO) or you can
  603.     leave that issue up to the user.
  604.  
  605.     Now, given the above, the following bits of code can be
  606.     used to get the debugger to switch into single-step mode
  607.     at the point of the Enforcer hit.  You can also set some
  608.     data value here to tell your debugger about this.
  609.  
  610.     ;
  611.     ; The following code is inserted into the bus error vector.
  612.     ; Make sure you follow the VBR to find the vector.
  613.     ; Store the old vector in the address OldVector
  614.     ; Make sure you already have the single-step trap vector
  615.     ; installed before you install this.  Note that any extra
  616.     ; code you add in the comment area *MUST NOT* cause a bus
  617.     ; fault of any kind, including reading of location 4.
  618.     ;
  619.     ; This is the common part...
  620.     ;
  621.     EnforcerHit:    ds.l    1                       ; Some private flag
  622.     MyTask:         ds.l    1                       ; Task under test
  623.     MyExecBase:     ds.l    1                       ; The local copy
  624.     OldVector:      ds.l    1                       ; One long word
  625.                     ;
  626.                     ; Now, if you wish to only trap a specific task,
  627.                     ; do the check at this point.  For example, a
  628.                     ; simple single-task debugger would do something
  629.                     ; like this:
  630.     Common:         move.l  a0,-(sp)                ; Save this...
  631.                     move.l  MyExecBase(pc),a0       ; Get ExecBase...
  632.                     move.l  ThisTask(a0),a0         ; Get ThisTask
  633.                     cmp.l   MyTask(pc),a0           ; Are they the same?
  634.                     move.l  (sp)+,a0                ; Restore A0 (no flags)
  635.                     bne.s   TraceSkip               ; If not my task, skip
  636.                     ;
  637.                     bset.b  #7,(sp)                 ; Set trace bit...
  638.                     ; If you have any other data to set, do it now...
  639.                     ; Set as setting the EnforcerHit bit in your data...
  640.                     addq.l    #1,EnforcerHit          : Count the hit...
  641.                     ;
  642.     TraceSkip:      move.l  OldVector(pc),-(sp)     ; Ready to return
  643.                     rts
  644.     ;
  645.     ; This is the 68020/68030 version...
  646.     ;
  647.     NewVector030:   cmp.l   #4,$10(sp)              ; 68020 and 68030
  648.                     beq.s   TraceSkip               ; If AbsExecBase, OK
  649.                     bra.s    Common            ; Do the common stuff
  650.     ;
  651.     ; This is the 68040 version...
  652.     ;
  653.     NewVector040:   cmp.l   #4,$14(sp)              ; 68040
  654.                     beq.s   TraceSkip               ; If AbsExecBase, OK
  655.                     bra.s    Common            ; Do the common stuff
  656.     ;
  657.     ; This is the 68060 version...
  658.     ;
  659.     NewVector060:   cmp.l   #4,$08(sp)              ; 68060
  660.                     beq.s   TraceSkip               ; If AbsExecBase, OK
  661.                     bra.s    Common            ; Do the common stuff
  662.  
  663.  
  664.    DEBUGGERS:  NOT CAUSING A HIT
  665.     In order not to cause Enforcer hits, you can do a number
  666.     of things.  The easiest is to test the address with the TypeOfMem()
  667.     EXEC function.  If TypeOfMem() returns 0, the address is not
  668.     in the memory lists.  However, this does not mean it is not a
  669.     valid address in all cases.  (ROM, chip registers, I/O boards)
  670.     For those cases, you can build a "valid memory access table"
  671.     much like Enforcer does.  Here is the code from Enforcer for
  672.     the base memory tables:
  673.  
  674.     /*
  675.      * Mark_Address(mmu,start address,length,type)
  676.      */
  677.  
  678.     /*
  679.      * Special case the first page of CHIP RAM
  680.      */
  681.     mmu=Mark_Address(mmu,0,0x1000,INVALID | NONCACHEABLE);
  682.  
  683.     /*
  684.      * Map in the free memory
  685.      */
  686.     Forbid();
  687.     mem=(struct MemHeader *)SysBase->MemList.lh_Head;
  688.     while (mem->mh_Node.ln_Succ)
  689.     {
  690.       mmu=Mark_Address(mmu,
  691.                        (ULONG)(mem->mh_Lower),
  692.                        (ULONG)(mem->mh_Upper)-(ULONG)(mem->mh_Lower),
  693.                        ((MEMF_CHIP & TypeOfMem(mem->mh_Lower)) ?
  694.                          (NONCACHEABLE | VALID) : (CACHEABLE | VALID)));
  695.       mem=(struct MemHeader *)(mem->mh_Node.ln_Succ);
  696.     }
  697.     Permit();
  698.  
  699.     /*
  700.      * Map in the autoconfig boards
  701.      */
  702.     if (ExpansionBase=OpenLibrary("expansion.library",0))
  703.     {
  704.     struct    ConfigDev    *cd=NULL;
  705.  
  706.       while (cd=FindConfigDev(cd,-1L,-1L))
  707.       {
  708.         /* Skip memory boards... */
  709.         if (!(cd->cd_Rom.er_Type & ERTF_MEMLIST))
  710.         {
  711.           mmu=Mark_Address(mmu,
  712.                            (ULONG)(cd->cd_BoardAddr),
  713.                            cd->cd_BoardSize,
  714.                            VALID | NONCACHEABLE);
  715.         }
  716.       }
  717.       CloseLibrary(ExpansionBase);
  718.     }
  719.  
  720.     /*
  721.      * Now for the control areas...
  722.      */
  723.     mmu=Mark_Address(mmu,0x00BC0000,0x00040000,VALID | NONCACHEABLE);
  724.     mmu=Mark_Address(mmu,0x00D80000,0x00080000,VALID | NONCACHEABLE);
  725.  
  726.     /*
  727.      * and the ROM...
  728.      */
  729.     mmu=Mark_Address(mmu,
  730.                      0x00F80000,
  731.                      0x00080000,
  732.                      VALID | CACHEABLE | WRITEPROTECT);
  733.  
  734.     /*
  735.      * If the credit card resource, make the addresses valid...
  736.      */
  737.     if (OpenResource("card.resource"))
  738.     {
  739.       mmu=Mark_Address(mmu,0x00600000,0x00440002,VALID | NONCACHEABLE);
  740.     }
  741.  
  742.     /*
  743.      * If CD-based Amiga (CDTV, A570, etc.)
  744.      */
  745.     if (FindResident("cdstrap"))
  746.     {
  747.       mmu=Mark_Address(mmu,0x00E00000,0x00080000,VALID | NONCACHEABLE);
  748.       mmu=Mark_Address(mmu,0x00B80000,0x00040000,VALID | NONCACHEABLE);
  749.     }
  750.  
  751.     /*
  752.      * Check for ReKick/ZKick/KickIt
  753.      */
  754.     if ((((ULONG)(SysBase->LibNode.lib_Node.ln_Name)) >> 16) == 0x20)
  755.     {
  756.       mmu=Mark_Address(mmu,
  757.                        0x00200000,
  758.                        0x00080000,
  759.                        VALID | CACHEABLE | WRITEPROTECT);
  760.     }
  761.  
  762.    SEE ALSO
  763.     "A master's secrets are only as good as the
  764.      master's ability to explain them to others."  -  Michael Sinz
  765.  
  766.    BUGS
  767.     None?
  768.  
  769. FindHit                                                               FindHit
  770.  
  771.    NAME
  772.     FindHit - A tool that can locate the source file and line number
  773.               that a SegTracker report happened at.
  774.  
  775.    SYNOPSIS
  776.     FindHit will read the executable file and if there is debugging
  777.     information in it, will try to locate the source file and line
  778.     number that correspond to the Enforcer hit HUNK/OFFSET.
  779.  
  780.    FUNCTION
  781.     FindHit uses the Lattice/SAS/MetaScope standard 'LINE'
  782.     debug hunk to locate the closest line to the hunk/offset given.
  783.     Note that this can only happen if the executable has the
  784.     LINE debugging turned on.  (The LawBreaker program has this
  785.     such that you can test this yourself.)
  786.  
  787.     In SAS/C 6.x, you need to compile with DEBUG=LINE or better
  788.     and do not use the link option of NODEBUG.
  789.  
  790.     In SAS/C 5.x, you need to compile with -d1 or better.
  791.     Note that FindHit works with the old SAS/C 5.x 'SRC '
  792.     debugging information too.  This is required for -d2 or
  793.     higher debugging support.  However, I do not have 'SRC ' hunk
  794.     documentation and thus FindHit may be very specific to the
  795.     SAS/C 5.x version of this hunk.
  796.  
  797.     In DICE (2.07 registered being the one I tried) the -d1
  798.     debug switch also supports the 'LINE' debug hunk and
  799.     works with FindHit.
  800.  
  801.     In HX68 and CAPE, you need to add the DEBUG directive to
  802.     the assembly code program.  (See LawBreaker source)
  803.  
  804.     For other languages, or other versions of the above, please
  805.     see the documentation that comes with the language.
  806.  
  807.    INPUTS
  808.     FILE/A      - The executable file, with debugging information.
  809.  
  810.     OFFSETS/A/M - The HEX offset (with or without leading $)
  811.                   If a hunk number other than the default
  812.                   is needed, it is expressed as hunk:offset.
  813.                   The default hunk is that of the last argument
  814.                   or hunk 0 if no hunk number has been given.
  815.                   For example:  12 $22 $3:12 22 4:$12 32 $0:$32
  816.                   will find information for:
  817.                   hunk $0, offset $12
  818.                   hunk $0, offset $22
  819.                   hunk $3, offset $12
  820.                   hunk $3, offset $22
  821.                   hunk $4, offset $12
  822.                   hunk $4, offset $32
  823.                   hunk $0, offset $32
  824.  
  825.    EXAMPLE
  826.     FindHit FooBar $0342 $1:4F2 3:$1A 2C
  827.     badcode.c : Line 184
  828.     No line number information for Hunk $1, Offset $4F2
  829.     badcode2.c : Line 12
  830.     badcode2.c : Line 14
  831.  
  832.     See the Enforcer documentation about issues dealing with the
  833.     exact location of the Enforcer hit.  The line given may
  834.     not be exactly where the hit happened.
  835.  
  836.     The way I use this is to always have line debugging turned on
  837.     when I compile.  This does not change the quality of the code
  838.     and takes only a small amount of extra disk space.  However,
  839.     what I do is to link the program twice:  Once to a file called
  840.     program.ld which contains all of the debugging information.
  841.     Then, I link program.ld to program, stripping debug information.
  842.     The command line for SLINK or BLINK is as follows:
  843.  
  844.         BLINK program.ld TO program NODEBUG
  845.  
  846.     I keep both of these on hand; with program being the one I
  847.     distribute and use.  When a hit happens, I can just use program.ld
  848.     with FindHit to get the line number and source file that it happened
  849.     in.  This way you can distribute your software without the debugging
  850.     information and still be able to use FindHit on the actual code.
  851.     (After all, that link command does nothing but strip symbol and
  852.     debug hunks)
  853.  
  854.    NOTES
  855.     Note that this program does nothing when run from the Workbench
  856.     and thus does not have an icon.
  857.  
  858.    SEE ALSO
  859.     "Quantum Physics:  The Dreams that Stuff is made of." - Michael Sinz
  860.  
  861.    BUGS
  862.  
  863. LawBreaker                                                         LawBreaker
  864.  
  865.    NAME
  866.     LawBreaker - A quicky test of Enforcer
  867.  
  868.    SYNOPSIS
  869.     This is a quick test of Enforcer and its reporting abilities.
  870.  
  871.    FUNCTION
  872.     This program is used to make sure that Enforcer is correctly
  873.     installed and operating.  LawBreaker works from either the CLI
  874.     or Workbench.  It will try to read and write certain memory
  875.     areas that will cause an Enforcer hit or four.
  876.  
  877.     LawBreaker will also do an Alert to show how Enforcer reports
  878.     an Alert.
  879.  
  880.     Note that the LawBreaker executable has debugging information
  881.     in it (standard LINE format debug hunk) such that you can
  882.     try the FindHit program to find the line that causes the hit.
  883.  
  884.    INPUTS
  885.     Just run it...
  886.  
  887.    RESULTS
  888.     When running Enforcer, you will see some output from Enforcer.
  889.     Output on a 68030 machine would look something like this:
  890.  
  891. 25-Jul-93  17:15:04
  892. WORD-WRITE to  00000000        data=0000       PC: 0763857C
  893. USP:  07657C14 SR: 0004 SW: 04C1  (U0)(-)(-)  TCB: 07642F70
  894. Data: DDDD0000 DDDD1111 DDDD2222 DDDD3333 0763852A DDDD5555 DDDD6666 DDDD7777
  895. Addr: AAAA0000 AAAA1111 AAAA2222 AAAA3333 AAAA4444 0763852A 07400810 --------
  896. Stck: 00000000 0752EE9A 00002800 07643994 00000000 076786D8 000208B0 2EAC80EE
  897. Stck: 487AFD12 486C82C4 4EBA3D50 4EBAEA28 4FEF0014 52ACE2E4 204D43EC 88BC203C
  898. ----> 0763857C - "lawbreaker"  Hunk 0000 Offset 00000074
  899. Name: "Shell"  CLI: "LawBreaker"  Hunk 0000 Offset 00000074
  900.  
  901. 25-Jul-93  17:15:04
  902. LONG-READ from AAAA4444                        PC: 07638580
  903. USP:  07657C14 SR: 0015 SW: 0501  (U0)(F)(-)  TCB: 07642F70
  904. Data: DDDD0000 DDDD1111 DDDD2222 DDDD3333 0763852A DDDD5555 DDDD6666 DDDD7777
  905. Addr: AAAA0000 AAAA1111 AAAA2222 AAAA3333 AAAA4444 0763852A 07400810 --------
  906. Stck: 00000000 0752EE9A 00002800 07643994 00000000 076786D8 000208B0 2EAC80EE
  907. Stck: 487AFD12 486C82C4 4EBA3D50 4EBAEA28 4FEF0014 52ACE2E4 204D43EC 88BC203C
  908. ----> 07638580 - "lawbreaker"  Hunk 0000 Offset 00000078
  909. Name: "Shell"  CLI: "LawBreaker"  Hunk 0000 Offset 00000078
  910.  
  911. 25-Jul-93  17:15:04
  912. BYTE-WRITE to  00000101        data=11         PC: 0763858A
  913. USP:  07657C14 SR: 0010 SW: 04A1  (U0)(F)(D)  TCB: 07642F70
  914. Data: 00000000 DDDD1111 DDDD2222 DDDD3333 0763852A DDDD5555 DDDD6666 DDDD7777
  915. Addr: AAAA0000 AAAA1111 AAAA2222 AAAA3333 AAAA4444 0763852A 07400810 --------
  916. Stck: 00000000 0752EE9A 00002800 07643994 00000000 076786D8 000208B0 2EAC80EE
  917. Stck: 487AFD12 486C82C4 4EBA3D50 4EBAEA28 4FEF0014 52ACE2E4 204D43EC 88BC203C
  918. ----> 0763858A - "lawbreaker"  Hunk 0000 Offset 00000082
  919. Name: "Shell"  CLI: "LawBreaker"  Hunk 0000 Offset 00000082
  920.  
  921. 25-Jul-93  17:15:04
  922. LONG-WRITE to  00000102        data=00000000   PC: 07638592
  923. USP:  07657C14 SR: 0014 SW: 0481  (U0)(-)(D)  TCB: 07642F70
  924. Data: 00000000 DDDD1111 DDDD2222 DDDD3333 0763852A DDDD5555 DDDD6666 DDDD7777
  925. Addr: AAAA0000 AAAA1111 AAAA2222 AAAA3333 AAAA4444 0763852A 07400810 --------
  926. Stck: 00000000 0752EE9A 00002800 07643994 00000000 076786D8 000208B0 2EAC80EE
  927. Stck: 487AFD12 486C82C4 4EBA3D50 4EBAEA28 4FEF0014 52ACE2E4 204D43EC 88BC203C
  928. ----> 07638592 - "lawbreaker"  Hunk 0000 Offset 0000008A
  929. Name: "Shell"  CLI: "LawBreaker"  Hunk 0000 Offset 0000008A
  930.  
  931. 25-Jul-93  17:15:06
  932. Alert !! Alert 35000000     TCB: 07642F70     USP: 07657C10
  933. Data: 00000000 DDDD1111 DDDD2222 DDDD3333 0763852A DDDD5555 DDDD6666 35000000
  934. Addr: AAAA0000 AAAA1111 AAAA2222 AAAA3333 AAAA4444 0763852A 07400810 --------
  935. Stck: 076385A0 00000000 0752EE9A 00002800 07643994 00000000 0762F710 076305F0
  936. ----> 076385A0 - "lawbreaker"  Hunk 0000 Offset 00000098
  937.  
  938.     Now, using FindHit, you would type:
  939.  
  940.     FindHit LawBreaker 0:82
  941.  
  942.     and it will tell you the source file name and the line number
  943.     where the hit happened.  See the FindHit documentation.
  944.  
  945.    NOTES
  946.     If enforcer is not running, the program should not cause the
  947.     system to crash.  It will, however, write to certain areas
  948.     of low memory.  Also, it will cause read access of some
  949.     addresses that may not exist.  This may cause bus faults.
  950.  
  951.    SEE ALSO
  952.     "Quantum Physics:  The Dreams that Stuff is made of." - Michael Sinz
  953.  
  954.    BUGS
  955.     There are 4 known Enforcer hits in this code and 1 alert, however,
  956.     they will not be fixed.  ;^)
  957.  
  958. MMU                                                                       MMU
  959.  
  960.    NAME
  961.     MMU - A 68040/68060 MMU Mapping Tool
  962.  
  963.    SYNOPSIS
  964.     MMU is a tool for 68040/060 systems to display and/or change the MMU
  965.     configuration contained within.  MMU will display the tables as
  966.     compressed as possible, noting address ranges that are mapped the
  967.     same and only displaying one line for the whole range.
  968.  
  969.    INPUTS
  970.     ADDRESS/K    - Hex address to display (if not given, all)
  971.     SIZE/K        - Hex address size of address range
  972.     READWRITE    - Change address range to ReadWrite
  973.     READONLY    - Change address range to ReadOnly
  974.     VALID        - Change address range to VALID
  975.     INVALID        - Change address range to INVALID
  976.     CACHE        - Change address range to CACHE enable
  977.     NOCACHE        - Change address range to CACHE disable
  978.     COPYBACK    - Change address range to non-serialized
  979.     NOCOPYBACK    - Change address range to serialized
  980.     GLOBAL        - Change address range to GLOBAL
  981.     LOCAL        - Change address range to LOCAL
  982.     SUPERVISOR    - Change address range to SUPERVISOR-only
  983.     USER        - Change address range to USER access
  984.     VERBOSE        - Show the changes as they are made
  985.     NOSHOW        - Do not show the whole table
  986.  
  987.    RESULTS
  988.     On my A3000 with a 68040 installed and Enforcer running, the
  989.     MMU output looks as follows:  (No options)
  990.  
  991. Current 68040 MMU table setup:
  992. $00000000-$00000FFF->$00000000:  Local, User, Invalid, Read-Only,  Serialized
  993. $00001000-$001FFFFF->$00001000: Global, User,   Valid, Read/Write, Serialized
  994. $00200000-$00BBFFFF->$07542000:  Local, User, Invalid, Read-Only,  Serialized
  995. $00BC0000-$00BFFFFF->$00BC0000: Global, User,   Valid, Read/Write, Serialized
  996. $00C00000-$00D7FFFF->$07542000:  Local, User, Invalid, Read-Only,  Serialized
  997. $00D80000-$00DFFFFF->$00D80000: Global, User,   Valid, Read/Write, Serialized
  998. $00E00000-$00E8FFFF->$07542000:  Local, User, Invalid, Read-Only,  Serialized
  999. $00E90000-$00EAFFFF->$00E90000: Global, User,   Valid, Read/Write, Serialized
  1000. $00EB0000-$00EFFFFF->$07542000:  Local, User, Invalid, Read-Only,  Serialized
  1001. $00F00000-$00FFFFFF->$00F00000: Global, User,   Valid, Read-Only,    Copyback
  1002. $01000000-$073FFFFF->$07542000:  Local, User, Invalid, Read-Only,  Serialized
  1003. $07400000-$07F7FFFF->$07400000: Global, User,   Valid, Read/Write,   Copyback
  1004. $07F80000-$FFFFFFFF->$07542000:  Local, User, Invalid, Read-Only,  Serialized
  1005.  
  1006.    WARNING
  1007.     This tool is a hack and does not have any safeguards on the options.
  1008.     Use at your own risk.
  1009.  
  1010.    SEE ALSO
  1011.     "A master's secrets are only as good as the
  1012.      master's ability to explain them to others."  -  Michael Sinz
  1013.  
  1014.    BUGS
  1015.     None?
  1016.  
  1017. Move4K                                                                 Move4K
  1018.  
  1019.    NAME
  1020.     Move4K - Moves as much out of the lower 4K of RAM as possible
  1021.  
  1022.    SYNOPSIS
  1023.     On 68040 systems, as much of the lower 4K of CHIP RAM as possible
  1024.     is removed from system use.
  1025.  
  1026.    FUNCTION
  1027.     On 68040 systems the MMU page sizes are 4K and 8K.  Enforcer
  1028.     uses the 4K page size.  Since watching for hits of low memory
  1029.     is a vital part of Enforcer, this means that the first 4K
  1030.     of RAM will be marked invalid.  On current systems, only
  1031.     the first 1K of RAM is invalid and thus 3K of RAM in that
  1032.     first 4K will end up needing to be emulated in Enforcer.
  1033.     In order to reduce the overhead that this causes (and the
  1034.     major performance loss) this program will try to move as much
  1035.     from that first 4K as possible and make any of the free
  1036.     memory within the first 4K inaccessible.
  1037.  
  1038.     Enforcer itself also has this logic, but it may be useful
  1039.     to be able to run this program as the first program in
  1040.     the Startup-Sequence (*AFTER* SetPatch) to try to limit
  1041.     the number of things that may use the lower 4K of RAM.
  1042.  
  1043.    INPUTS
  1044.     Just run it...  Can be run from CLI or Workbench
  1045.  
  1046.    RESULTS
  1047.     Any available memory in the lower 4K of CHIP RAM is removed
  1048.     plus a special graphics buffer is moved if it needs to be.
  1049.     After running this program you may have a bit less CHIP RAM
  1050.     than before.  You can run this program as many times as you
  1051.     wish since it only moves things if it needs to.
  1052.  
  1053.    NOTES
  1054.     This program will do nothing on systems without a 68040.
  1055.     It does not, however, check for the MMU and thus it will
  1056.     move the lower 4K even if the CPU is not able to run Enforcer.
  1057.  
  1058.     V39 of the operating system already does have the lowest
  1059.     MMU page empty and thus this program will effectively do
  1060.     nothing under V39.
  1061.  
  1062.    SEE ALSO
  1063.     "Eloquence is vehement simplicity"
  1064.  
  1065.    BUGS
  1066.     None.
  1067.  
  1068. RebootOff                                                           RebootOff
  1069.  
  1070.    NAME
  1071.     RebootOff - A keyboard reset handler to turn off Enforcer
  1072.  
  1073.    SYNOPSIS
  1074.     This is a simple utility that will turn off Enforcer when a
  1075.     keyboard reset happens.
  1076.  
  1077.    FUNCTION
  1078.     This utility uses the feature of the A1000/A2000/A3000/A4000
  1079.     Amiga systems to turn off Enforcer when the user does a
  1080.     keyboard reset (ctrl-Amiga-Amiga).  This utility requires that
  1081.     your Amiga supports (in hardware) the keyboard reset system.
  1082.  
  1083.     The reason this was written was such that Enforcer could be
  1084.     "quit" just before you reboot your Amiga 3000.  This way
  1085.     it will let the kickstart not need to be reloaded and
  1086.     thus let utilities such as RAD: work across reboots.  Note
  1087.     that this does *not* help in the case where the Amiga reboots
  1088.     under software conditions.  It is only for keyboard resets.
  1089.  
  1090.    INPUTS
  1091.     Just run it from either the CLI or Workbench.  It installs
  1092.     a handler and exits.  On a keyboard reset, it will turn Enforcer
  1093.     off before it lets the reset continue...  (max time of 10 seconds)
  1094.  
  1095.    RESULTS
  1096.     Installs a small reset handler object and task into the system.
  1097.     About 3700 bytes needed the first time it is run.
  1098.  
  1099.    NOTES
  1100.     If Enforcer is not running, nothing will happen at Reset time.
  1101.     If Enforcer can not quit, the reset system will continue to try
  1102.     to quit Enforcer until the hardware timeout happens...
  1103.  
  1104.    SEE ALSO
  1105.     From the home of the imaginary deadlines:
  1106.     "It will take 2i weeks to do that project." - Michael Sinz
  1107.  
  1108. SegTracker                                                         SegTracker
  1109.  
  1110.    NAME
  1111.     SegTracker - A global SegList tracking utility
  1112.  
  1113.    SYNOPSIS
  1114.     A global tracking utility for disk loaded files including
  1115.     libraries and devices.  If placed in the startup-sequence
  1116.     right after SetPatch, it will track all disk loaded segments
  1117.     (other than those loaded by SetPatch)
  1118.  
  1119.    FUNCTION
  1120.     SegTracker will patch the DOS LoadSeg(), NewLoadSeg(), and UnLoadSeg()
  1121.     functions in order to track the SegLists that are loaded.
  1122.     SegTracker keeps these seglist stored in a "safe" manner and
  1123.     even handles programs which SegList split.
  1124.  
  1125.     The first time the program is run, it installs the patches
  1126.     and semaphore.  After that point, it just finds the semaphore
  1127.     and uses it.
  1128.  
  1129.     When SegTracker is installed, it will scan the ROM for ROM modules
  1130.     and add their locations to the tracking list such that addresses
  1131.     within those modules can be identified.  Note that the offsets
  1132.     from the module is based on the location of the module's ROMTAG.
  1133.     The NOROM option will prevent this feature from being installed.
  1134.  
  1135.     By using SegTracker, it will be possible to better identify
  1136.     where Enforcer hits come from when dealing with libraries
  1137.     and devices.  Basically, it is a system-global Hunk-o-matic.
  1138.  
  1139.     External programs can then pass in an address to SegTracker
  1140.     either via the command line or via the given function pointer
  1141.     in the SegTracker semaphore and get back results as to what
  1142.     hunk and offset the address is at.
  1143.  
  1144.     To work with the function directly, you need to find the
  1145.     the semaphore of "SegTracker" using FindSemaphore().
  1146.     The structure found will be the following:
  1147.  
  1148.     struct  SegSem
  1149.     {
  1150.     struct  SignalSemaphore seg_Semaphore;
  1151.             SegTrack        *seg_Find;
  1152.     };
  1153.  
  1154.     The function pointer points to a routine that takes an address
  1155.     and two pointers to long words for returning the Segment number
  1156.     and Offset within the segment.  The function returns the name
  1157.     of the file loaded.  Note that you must call this function
  1158.     while in Forbid() and then copy the name as the seglist may
  1159.     be UnLoadSeg'ed at any moment and the name string will then
  1160.     no longer be in memory.
  1161.  
  1162.     typedef    char (* __asm SegTrack(register __a0 ULONG Address,
  1163.                                    register __a1 ULONG *SegNum,
  1164.                                    register __a2 ULONG *Offset));
  1165.  
  1166.     The above is for use in C code function pointer prototype
  1167.     in SAS/C 5 and 6.
  1168.  
  1169.    INPUTS
  1170.     SHOW/S  - Shows all of the segments being tracked.
  1171.  
  1172.     DUMP/S  - Displays all of the segment elements being tracked.
  1173.  
  1174.     NOROM/S - Tells segtracker not to scan ROM when it is
  1175.               installed, thus not adding ROM addresses to the
  1176.               tracking list.
  1177.  
  1178.     FIND/M  - Find the hex (in $xxxxx format) address in
  1179.               the tracked segments.  Multiple addresses
  1180.               can be given.
  1181.  
  1182.     Options are not available from Workbench as they require
  1183.     the CLI.  However, you can run SegTracker from Workbench
  1184.     to install it.
  1185.  
  1186.    EXAMPLE USAGE
  1187.     /*
  1188.      * A simple program that will "find" given addresses in the SegLists
  1189.      * This program has been compiled with SAS/C 6.2 without errors or
  1190.      * warnings.
  1191.      *
  1192.      * Compiler options:
  1193.      * DATA=FARONLY PARAMETERS=REGISTER NOSTACKCHECK
  1194.      * NOMULTIPLEINCLUDES STRINGMERGE STRUCTUREEQUIVALENCE
  1195.      * MULTIPLECHARACTERCONSTANTS DEBUG=LINE NOVERSION
  1196.      * OPTIMIZE OPTIMIZERINLOCAL NOICONS
  1197.      *
  1198.      * Linker options:
  1199.      * FindSeg.o TO FindSeg SMALLCODE SMALLDATA NODEBUG LIB LIB:sc.lib
  1200.      */
  1201.     #include <exec/types.h>
  1202.     #include <exec/execbase.h>
  1203.     #include <exec/libraries.h>
  1204.     #include <exec/semaphores.h>
  1205.     #include <dos/dos.h>
  1206.     #include <dos/dosextens.h>
  1207.     #include <dos/rdargs.h>
  1208.  
  1209.     #include <clib/exec_protos.h>
  1210.     #include <pragmas/exec_sysbase_pragmas.h>
  1211.  
  1212.     #include <clib/dos_protos.h>
  1213.     #include <pragmas/dos_pragmas.h>
  1214.  
  1215.     #include <string.h>
  1216.  
  1217.     #include "FindSeg_rev.h"
  1218.  
  1219.     #define EXECBASE (*(struct ExecBase **)4)
  1220.  
  1221.     typedef char (* __asm SegTrack(register __a0 ULONG,
  1222.                                    register __a1 ULONG *,
  1223.                                    register __a2 ULONG *));
  1224.  
  1225.     struct SegSem
  1226.     {
  1227.     struct SignalSemaphore seg_Semaphore;
  1228.            SegTrack        *seg_Find;
  1229.     };
  1230.  
  1231.     #define SEG_SEM "SegTracker"
  1232.  
  1233.     #define TEMPLATE "FIND/M" VERSTAG
  1234.  
  1235.     #define OPT_FIND  0
  1236.     #define OPT_COUNT 1
  1237.  
  1238.     ULONG cmd(void)
  1239.     {
  1240.     struct ExecBase *SysBase;
  1241.     struct Library  *DOSBase;
  1242.     struct RDArgs   *rdargs;
  1243.            ULONG    rc=RETURN_FAIL;
  1244.     struct SegSem   *segSem;
  1245.            char     **hex;
  1246.            LONG     opts[OPT_COUNT];
  1247.  
  1248.       SysBase = EXECBASE;
  1249.       if (DOSBase = OpenLibrary("dos.library",37))
  1250.       {
  1251.         memset((char *)opts, 0, sizeof(opts));
  1252.  
  1253.         if (!(rdargs = ReadArgs(TEMPLATE, opts, NULL)))
  1254.         {
  1255.           PrintFault(IoErr(),NULL);
  1256.         }
  1257.         else if (CheckSignal(SIGBREAKF_CTRL_C))
  1258.         {
  1259.           PrintFault(ERROR_BREAK,NULL);
  1260.         }
  1261.         else if (segSem=(struct SegSem *)FindSemaphore(SEG_SEM))
  1262.         {
  1263.           rc=RETURN_OK;
  1264.           if (opts[OPT_FIND])
  1265.           {
  1266.             for (hex=(char **)opts[OPT_FIND];(*hex);hex++)
  1267.             {
  1268.             char  *p;
  1269.             ULONG val;
  1270.             ULONG tmp[4];
  1271.             ULONG c;
  1272.  
  1273.               val=0;
  1274.               p=*hex;
  1275.               if (*p=='$') p++; /* Support $hex */
  1276.               while (*p)
  1277.               {
  1278.                 c=(ULONG)*p;
  1279.                 if ((c>='a') && (c<='f')) c-=32;
  1280.                 c-='0';
  1281.                 if (c>9)
  1282.                 {
  1283.                   c-=7;
  1284.                   if (c<10) c=16;
  1285.                 }
  1286.  
  1287.                 if (c<16)
  1288.                 {
  1289.                   val=(val << 4) + c;
  1290.                   p++;
  1291.                 }
  1292.                 else
  1293.                 {
  1294.                   val=0;
  1295.                   p=&p[strlen(p)];
  1296.                 }
  1297.               }
  1298.  
  1299.               /*
  1300.                * Ok, we need to do this within Forbid()
  1301.                * as segments can unload at ANY time, including
  1302.                * during AllocMem(), so we use a stack buffer...
  1303.                *
  1304.                */
  1305.               Forbid();
  1306.               if (p=(*segSem->seg_Find)(tmp[0]=val,&tmp[2],&tmp[3]))
  1307.               {
  1308.               char Buffer[200];
  1309.  
  1310.                 stccpy(Buffer,p,200);
  1311.                 tmp[1]=(ULONG)Buffer;
  1312.                 VPrintf("$%08lx - %s : Hunk %ld, Offset $%08lx",tmp);
  1313.  
  1314.                 /*
  1315.                  * Now get the SegList address by passing the
  1316.                  * same pointer for both hunk & offset.  Note
  1317.                  * that this is only in the newer SegTrackers
  1318.                  * To test if this worked, check if the result
  1319.                  * of this call is either a hunk or an offset.
  1320.                  */
  1321.                 (*segSem->seg_Find)(val,&tmp[0],&tmp[0]);
  1322.                 /*
  1323.                  * This "kludge" is for compatibility reasons
  1324.                  * Check if result is the same as either the hunk
  1325.                  * or the offset.  If so, do not print it...
  1326.                  */
  1327.                 if ((tmp[0]!=tmp[2]) && (tmp[0]!=tmp[3]))
  1328.                 {
  1329.                   VPrintf(", SegList $%08lx",tmp);
  1330.                 }
  1331.  
  1332.                 PutStr("\n");
  1333.               }
  1334.               else VPrintf("$%08lx - Not found\n",tmp);
  1335.               Permit();
  1336.             }
  1337.           }
  1338.         }
  1339.         else PutStr("Could not find SegTracker semaphore.\n");
  1340.  
  1341.         if (rdargs) FreeArgs(rdargs);
  1342.         CloseLibrary(DOSBase);
  1343.       }
  1344.       else if (DOSBase=OpenLibrary("dos.library",0))
  1345.       {
  1346.         Write(Output(),"Requires Kickstart 2.04 (37.175) or later.\n",43);
  1347.         CloseLibrary(DOSBase);
  1348.       }
  1349.  
  1350.       return(rc);
  1351.     }
  1352.  
  1353.    NOTES
  1354.     The earlier this command is run, the better off it will be in
  1355.     tracking disk loaded segments.  Under debug usage, you may
  1356.     wish to run the command right *AFTER* SetPatch.
  1357.  
  1358.     Some things may not call UnLoadSeg() to free their seglists.
  1359.     There is no way SegTracker can follow a seglist that is not
  1360.     unloaded via the dos.library call to UnLoadSeg().  For this
  1361.     reason, SegTracker adds new LoadSeg() segments to the top
  1362.     of its list.  This way, if any old segments are still on
  1363.     the list but have been unloaded via some other method
  1364.     they will not clash with newer segments during the find operation.
  1365.  
  1366.     Note that the resident list is one such place where
  1367.     UnLoadSeg() is not called to free the seglist.  Thus,
  1368.     if something is made resident and then later unloaded
  1369.     it will still be listed as tracked by SegTracker.
  1370.  
  1371.     In order to support a new feature in CPR, the SegTracker function
  1372.     got a "kludge" added to it.  If a segment is found, you can then
  1373.     call the function again with the same address but with having
  1374.     both pointers point to the same longword of storage.  By doing
  1375.     this, the function will now return (in that longword) the
  1376.     SegList pointer (CPTR not BPTR) of the file that contains
  1377.     the address.  The reason this method was used was so it
  1378.     would be compatible with older SegTracker versions.  In older
  1379.     versions you would not get the result you wanted but you would
  1380.     also not crash.  See the example above for more details on how
  1381.     to use this feature.  The SegTracker FIND option has been
  1382.     expanded to include this information.
  1383.  
  1384.     Due to the fact that I am working on a design of a new set of
  1385.     debugging tools (Enforcer/SegTracker/etc)  I do not wish to
  1386.     expand the current SegTracker model in too many ways.
  1387.  
  1388.    SEE ALSO
  1389.     "Quantum Physics:  The Dreams that Stuff is made of." - Michael Sinz
  1390.  
  1391.    BUGS
  1392.  
  1393.